性能优化// https://blog.csdn.net/weixin_33976072/article/details/93168109
//** */ v-if和v-for同时执行的优先级问题
//1.v-for的优先级要高于v-if 在源码中我们其实可以看到 v-if v-else-if v-else被封装为一个函数 
// 在执行v-for时候作为代码实现的一个参数在v-for遍历的时候依次执行这函数来输出数据
//2.在同时执行的时候都会先执行循环在判断条件，循环无论如何都不能避免 浪费性能
//3.可以在外面嵌套templete进行v-if判断 在内部进行v-for循环
//4.如果需要在循环内部v-if的话 可以通过计算属性提前过滤掉这些不需要显示的项

//** */ vue组件data为什么必须是个函数而vue的跟实例则没有此限制
// vue组件可能存在多个实例，如果使用对象定义data则会导致公用一个data对象，那么状态的变更会影响所有组件的实例这不合理
// 采用函数定义在initData的时候会作为一个工厂函数返回全新的data对象，避免多实例间状态的污染，而vue的根实例只有一个在创建的时候不存在这个限制

//** */ vue中key的作用和原理
//1. key的作用是为了高效更新虚拟dom,原理是vue在patch过程中可以通过key精准判断两个节点是否是同一个，
// 避免了vue就地更新的策略避免频繁更新不同元素，减少了dom操作量，提高性能
//2. 避免了一些隐藏的bug，不设置key的话 如果对列表中间元素做删除操作 根据vue就地复用的原理 本身删除中间元素结果可能会变成删除了最后一个元素
// 这里详情参考https://www.zhihu.com/question/61064119
//3.相同标签元素过渡切换的时候也会用到key，不然会复用这个元素渲染元素的内容，会出现内容改变了，但是没有过渡的效果


//** */你怎么理解vue中diff算法
// 1.diff算法是虚拟dom技术下的必然产物，通过新旧虚拟dom的对比，将变化的地方更新在真实的dom上面，同时也西药diff高效的执行对比的过程
// 2.vue2.x中每一个组件只有一个watcher与之对应，只有引入diff才能精确的找到发生变化的地方
// 3.vue中diff执行的时刻是组件实例执行其更新函数时，他会对比上一次的渲染结果oldVnode和新的渲染结果newVnode，此过程称为patch
    // watcher的调用执行了更新函数，当我们修改一个数据的时候由于数据的响应式触发了set，set中触发了通知，通知会尝试将watcher添加到异步更新队列，
    // 在每次事件循环结束的时候会去清空这些队列，清空的过程中所有的watcher会尝试去执行更新函数，更新函数执行的时候会去调用组件的渲染函数和更新函数
    // 会重新渲染最新的虚拟dom
// 4.diff遵循 深度优先，同级比较，两个节点比较的时候会先判断他们是否拥有子节点或者文本节点
    //首尾进行四次比较，如果没有找到相同的节点则按照通用的方式遍历查找，查找结束后再按照情况处理剩下的节点，比如一方已经查找完，另一个还有
    //进行批量的新增或者删除等。通常我们借助key可以精确的找到相同的节点，整个patch过程非常高效


//** */ vue有哪些性能优化的方法
// 1.路由懒加载
// 2.keep-alive缓存页面
// 3.v-show复用dom
// 4.v-for遍历的同时避免使用v-if 可以使用computed将数据过滤 
// 5.长列表性能优化 
        // 1).纯粹的数据展示没有任何改变不需要做响应式 
        // 2).大数据长列表，可采用虚拟滚动，只渲染少部分区域内容 参考vue-virtual-scroller、vue-virtual-scroll-list
        // 3).参考longList进行说明
// 6.vue-lazyload 图片懒加载，当图片过多的时候未出现再可视区域先不做加载，滚动到可视区域的时候再进行加载
// 7.组件库按需引入
// 8.无状态组件标记为函数组件<template functional> 没有响应式的数据
// 9.子组件分割
// 10.变量本地化 比如某个方法中频繁调用this中的data,可以在方法内部再定义下 

//** */ vue3.0有哪些新特性
// 性能方面
// 1).虚拟dom的重写, vue2的diff是全量比较，很多静态节点不会发生变化，就浪费了性能
    // vue3会根据这些节点的内容和属性会不会发生变化添加静态标记，diff的时候只会对比这些带有静态标记的节点
// 2).静态提升 vue2中无论元素是否参与更新都会进行创建 _createVNode，然后进行渲染
    // vue3使用静态提升后，对于不参与更新的元素只会创建一次，在渲染的时候直接复用
// 3)cacheHandlers 事件侦听器缓存  默认情况下onClick会被视为动态绑定, 所以每次都会去追踪它的变化
    // 开启cacheHandlers后 因为是同一个函数，所以没有追踪变化, 直接缓存起来复用即可
    // 暂时还不知道怎么开启，后面再研究下
// 4) 基于Proxy的响应式系统
    //vue2使用defineProperty 在响应过程中递归遍历每一个属性消耗较大，属性的新增和删除无法监听到，
    // 数组响应化需要监听原型方法额外实现，当利用索引修改数组项的时候 或者修改数组长度的时候都需要额外的方法操作
    
    // vue3使用Proxy来实现监听 Proxy可以理解为一到关卡，外界访问对象的时候必须先通过这个拦截，可以直接监听对象而非属性
        // 监听数组的变化， Proxy返回的是一个新对象 可以直接操作新的对象达到目的 defineProperty只能遍历对象属性进行修改
        // Proxy可以直接监听对象，而非属性，可以监听属性的增加
        // Proxy可以监听数组
        // Proxy有很多Object.defineProperty不具备的拦截方法
        // Proxy返回一个新对象，可以直接操作新对象达到目的，Object.defineProperty只能遍历对象属性修改
//体积更小 通过tree-shaking摇树优化库的体积 ，只会打包用到的api
// TypeScript支持，编辑器能提供强有力的类型检查和错误及警告
// Composition API 这个可以扩展来说
// 独立的响应化模块


//** */ vuex的使用和理解
// vuex是vue的一个状态管理系统，他会几种存储管理组件的状态
// state, mutations,actions,getters

//** */ vue组件的通信方式
// 1.props
// 2.$emit/$on 事件总线 可以跨层级使用
// 3.vuex 状态管理
// 4.. $parent/$children （父 = 子 项目中不建议使用）缺点：不可跨层级
// 5.$attrs/$listeners 就是props中没有包含的属性会在$attr中 （皆可 如果搞不明白 不建议和面试官说这一种）
// 6.provide/inject ★★★ （高阶用法 = 推荐使用 ） 优点：使用简单 缺点：不是响应式 可以通过响应式包裹实现响应式

//** */  vue-router中的导航钩子有哪些
// 1.全局钩子函数 beforeEach (to，from，next) 路由改变前调用 多用来进行账号验证
    // afterEach (to，from) 路由改变后的钩子
// 2.路由配置中的导航钩子
    // beforeEnter (to，from，next) 是在router的配置文件中使用
// 3.组件内的钩子函数
    // 1. beforeRouteEnter (to,from,next)
    // 该组件的对应路由被 comfirm 前调用。
    // 此时实例还没被创建，所以不能获取实例（this） 
    // 2. beforeRouteUpdate (to,from,next)
    // 当前路由改变，但改组件被复用时候调用
    // 该函数内可以访问组件实例(this)
    // 3. beforeRouteLeave (to,from,next)
    // 当导航离开组件的对应路由时调用。
    // 该函数内可以访问获取组件实例（this）
// 路由的变化可以 使用watch 来对$route 监听

//** */  说说vue响应式理解 用自己的理解去说
// https://www.cnblogs.com/fundebug/p/responsive-vue.html
// 在vue init的过程中data通过observer转换成getter和setter形式来对数据的变化进行追踪，
// 当对象被读取的时候会执行getter函数，被赋值的时候执行setter函数
// 当外界通过Watcher读取数据时，会触发getter从而将Watcher添加到依赖中。
// 在修改对象的值的时候，会触发对应的setter， setter通知之前依赖收集得到的 Dep 中的每一个 Watcher，告诉它们自己的值改变了，需要重新渲染视图。
// 这时候这些 Watcher就会开始调用 update 来更新视图。

//** */  vue为什么要求组件模版只能有一个根元素?
// 1)一个vue单文件组件就是一个vue实例，如果template下有多个div那么如何指定vue实例的根入口呢，
    // 为了让组件可以正常生成一个vue实例，这个div会自然的处理成程序的入口，通过这个根节点，来递归
    // 遍历整个vue树下的所有节点，并处理为vdom，最后再渲染成真正的HTML，插入在正确的位置。
// 2)vue3.0中允许template下有多个根节点 vue3支持Fragment 他是虚拟的不会在dom树中渲染
    // 这样我们就可以将组件功能绑定到单个元素中，而无需创建冗余的 DOM 节点

//** */    watch和computed的区别以及怎么选用
// watch更加通用  ，computed计算底层来着于watch 但做了缓存相关的操作
// watch当数据变化时执行异步操作，或者开销较大的时候，比如一条数据的改变会影响多条数据
// computed 简单高效/只有依赖数据改变的时候才会执行/优先使用 对于任何复杂逻辑或一个数据属性在它所依赖的属性发生变化时，也要发生变化，简单讲。当一个属性
    // 受多个属性影响的时候，例如 购物车商品结算时


//** */   你知道nextTick的原理吗?
// 在dom更新完成后执行的一个回调函数
// 1. vue用异步队列的方式来控制DOM更新和nextTick回调先后执行
// 讲一下事件循环和微任务宏人物
// 2. microtask/微任务因为其高优先级特性，能确保队列中的微任务在一次事件循环前被执行完毕
// 3. 因为兼容性问题，vue不得不做了microtask向macrotask的降级方案

//** */ vue双向绑定原理
// 讲解下响应式原理 
// 按照图片内容讲解 可以再详细一些
// view => model 监听外部修改设置属性值，执行更新的时候会进行判断旧值和新值是否相等，不等才会更新

//** */ vue生命周期
// Vue 实例有一个完整的生命周期，也就是从开始创建、初始化数据、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载等一系列过程，我们称这是Vue的生命周期。
// 根据图片分析
// new Vue():初始化实例 （初始化事件(on/once/off/emit)和生命周期(mount/forceUpdate/nextTick/destroy)）
// beforeCreate : 实例初始化之后,此时还不能够访问data/prop的数据 有一些默认属性和事件，data和methods还没完成初始化 还不可用
    // init injections & reactivity（通过依赖注入导入依赖项）数据响应式
// created 实例创建完成，属性已经绑定 这个时候可以访问到数据 data和methods watcher和event
    // 检查vue的配置，即new Vue() 里面的el项是否存在 有就继续检查template项。没有则等到手动绑定调用vm.$mount()
    // 检查template项，没有的话就被绑定区域的el对象的outerHTML 然后执行相关的render函数
// beforeMount 这个时候el已经创建完成了，只是还没有挂载到dom上 el是指的vue自己的dom结构 
    // 编译替换被绑定的模板 ,模板语法被真实数据替换 比如{{}}  $el挂载到dom上
// mounted 实例被挂载后调用  mounted不会保证所有子组件一起挂载。
// 5.beforeupdata：数据更新时调用，发生在虚拟dom打补丁前，这时适合在更新前访问现有dom，如
// 手动移除已添加的事件监听器。
// 6.updated：在数据变更导致的虚拟dom重新渲染和打补丁后，调用该钩子。当这个钩子被调用时，组
// 件dom已更新，可执行依赖于dom的操作。多数情况下应在此期间更改状态。 如需改变，最好使用
// watcher或计算属性取代。注意updated不会保证所有的子组件都能一起被重绘。
// 7.beforedestory：在实例销毁之前调用。在这时，实例仍可用。
// 8.destroyed：实例销毁后调用，这时vue实例的所有指令都被解绑，所有事件监听器被移除，所有子实
// 例也被销毁。
mvvm
// model层 数据层,数据的模型，数据存储
// 对应数据层的域模型，它主要做域模型的同步。通过 Ajax/fetch 等 API 完成客户端和服务端业务 Model 的同步。
// 在层间关系里，它主要用于抽象出 ViewModel 中视图的 Model。
// View 层:作为视图模板存在，在 MVVM 里，整个 View 是一个动态模板。除了定义结构、布局外，它展示的是 ViewModel 层的数据和状态。
// View 层不负责处理状态，View 层做的是 数据绑定的声明、 指令的声明、 事件绑定的声明。
// ViewModel 层:把 View 需要的层数据暴露，并对 View 层的 数据绑定声明、 指令声明、 事件绑定声明 负责，也就是处理 View 层的具体业务逻辑。
// ViewModel 底层会做好绑定属性的监听。
// 当 ViewModel 中数据变化，View 层会得到更新；而当 View 中声明了数据的双向绑定（通常是表单元素），框架也会监听 View 层（表单）值的变化。
// 一旦值变化，View 层绑定的 ViewModel 中的数据也会得到自动更新。

// 分离视图（View）和模型（Model）,降低代码耦合，提高视图或者逻辑的重用性: 比如视图（View）可以独立于Model变化和修改，一个ViewModel可以绑定不同的"View"上，当View变化的时候Model可以不变，当Model变化的时候View也可以不变。
// 你可以把一些视图逻辑放在一个ViewModel里面，让很多view重用这段视图逻辑
// 提高可测试性: ViewModel的存在可以帮助开发者更好地编写测试代码
// 自动更新dom: 利用双向绑定,数据更新后视图自动更新,让开发者从繁琐的手动dom中解放

vue组件通信
// props/$emit+v-on: 通过props将数据自上而下传递，而通过$emit和v-on来向上传递信息。
// EventBus: 通过EventBus进行信息的发布与订阅
// vuex: 是全局数据管理库，可以通过vuex管理全局的数据流
// $attrs/$listeners: Vue2.4中加入的$attrs/$listeners可以进行跨级的组件通信 不作为props接收的属性 都会成为$attrs。  inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在props声明的属性
// provide/inject：以允许一个祖先组件向其所有子孙后代注入一个依赖，不论组件层次有多深，并在起上下游关系成立的时间里始终生效，这成为了跨组件通信的基础


前端工程化
Babel的原理是什么
// 解析 Parse: 将代码解析⽣成抽象语法树( 即AST )，即词法分析与语法分析的过程 
// 转换 Transform: 对于 AST 进⾏变换⼀系列的操作，babel 接受得到 AST 并通过 babel-traverse 对其进⾏遍历，在 此过程中进⾏添加、更新及移除等操作 
// ⽣成 Generate: 将变换后的 AST 再转换为 JS 代码, 使⽤到的模块是 babel-generator
// 我们平常写的babel插件都是对Transform后的AST进行一系列的操作









